﻿#define DKISDEBUGGING 

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
using System.Collections.Generic;
using System.Text;

namespace NMbsDuplex.TCPServerX.Deamon
{
    using DrDimsLib.CoreSDK.Functionality;
    using System.IO;

    /* Bifrost 代码灵感 - 北欧神话中的【彩虹桥】*/
    public sealed class Bifrost : TCPBase
    {
        public Bifrost(Int32 port) : base(port)
        {
            MaxNodesCount = 120;
            ManagedQueueLength = (int)(MaxNodesCount * 0.75);

            Listener.Bind(new IPEndPoint(IPAddress.Any, port/*TCP多重端口绑定*/));
            Listener.Listen(ManagedQueueLength/* 默认的TCP排队等待长度 */); 
            LogSystemInfo(/*启动日志系统*/);
            
            /*消息队列推送管道 - 作为主进程的一个子线程充当控制台服务器的消息推送管道*/
            Task.Run( ()=> PushMsg() );

            /* Ω双工服务线程池Ω */
            while (true)
            {
                Socket forkChild = Listener.Accept();
                // 添加用户到 | 数.据.链.表 |
                RegisterDict4Domain[CoreInjector.NodeLargen](forkChild);

                /* 
                 * 每一个线程内部的内存单元 都***ShouldNot不应该*** 
                 * 干扰到系统进程和推送线程
                 */
                Task.Run(() =>
                {
                    Push1st(forkChild); // Greeting
                }).ContinueWith(task =>
                {
                    PullMsg(forkChild);
                });
            }
        }

        /// <summary>
        /// 处理Server端的**消息推送管道** 宿主为异步后台线程
        /// </summary>
        private void PushMsg()
        {
            var buffer = new byte[TCPExtension.PACKSIZE];
            string ServMsg = string.Empty;
            while ((ServMsg = Console.ReadLine()) != null)
            {
                // 链表长度检查 - 使用指针地址节点Node是没有一丁点性能损耗的  
                // 广东人喜欢用List<Node> 我觉得是非常愚蠢的
                if (LinkedInUsers.Count == 0)
                {
                    Console.WriteLine("链表节点为空 跳过无效推送...");
                    continue;
                }
                // 推送的V1版本为同步 数据结构为`双向链表` 访问方式为轮训
                LinkedInUsers.ToList().ForEach(Node =>
                {
                    // *** 消息队列推送管道 *** 
                    Socket sock = Node.Value.refSock;
                    sock.QosSend("ServPush[消息推管道]~>: " + ServMsg);
                });
                Thread.Sleep(PushInterval);
            }
        }
        /// <summary>
        /// Socket消息处理主函数 根据自然语言传输协议 进行逻辑分路
        /// </summary>
        /// <param name="SockRef"> SockRef文件描述符 </param>
        private void PullMsg(Socket SockRef)
        {
            // 2.Server端Pull异步接受线程 1:1
            int N = 0;
            while (true)
            {
                string receivingMsg = SockRef.QosRecv(ref N);
                if (N > 0)
                {
                    if (FindRoadMap(SockRef, receivingMsg) != true)
                    {
                        Console.WriteLine("Server端口正常断开");
                        return;
                    }
                }
                else
                {
                    /* 网卡缓冲区异常 - `漏水处理` */
                    RegisterDict4Domain[CoreInjector.NodeSqueeze](SockRef);
                    Console.WriteLine("漏水处理");
                    break;
                }
            }
        }

        /// <summary>
        /// Socket传输解码层 - 上层BLL解析自然语言首部
        /// </summary>
        /// <param name="refSock"> 文件描述符 </param>
        /// <param name="receivingMsg"> 传输字节流 </param>
        /// <returns></returns>
        protected internal override bool FindRoadMap(Socket refSock, string receivingMsg)
        {
            bool isContinue = base.FindRoadMap(refSock, receivingMsg);
            // 这里 将会产生大量的业务逻辑代码 推荐使用 1.依赖注入 2.函数指针字典
            /* 停止用水 - 客户端主动关闭 */

            if (receivingMsg.StartsWith(Tokenizer.TPIN))
            {
                HandlePing(refSock, Tokenizer.TPIN);
            }else if (receivingMsg.StartsWith(Tokenizer.TSyn))
            {
                HandlePing(refSock, receivingMsg);
            }
            else if (receivingMsg.StartsWith(Tokenizer.TFin))
            {
                HandlePing(refSock, receivingMsg);
                RegisterDict4Domain[CoreInjector.NodeSqueeze](refSock);
                isContinue = false;
            }
            else if (receivingMsg.StartsWith(Tokenizer.TBiz))
            {
                HandlePing(refSock, receivingMsg);
            }
            else if (receivingMsg.StartsWith(Tokenizer.TFile))
            {
                translateFile(refSock,receivingMsg);
            }else 
            {
                var pingInfo = "未经过协议解析 `空Ping`" + " [`" + receivingMsg + "`]";
                HandlePing(refSock, pingInfo);
            }
            return isContinue;
        }

        /// <summary>
        /// 首次接入 Server推送一次欢迎信息
        /// </summary>
        /// <param name="SockBlockPtr"> 文件描述符 </param>
        private void Push1st(Socket SockBlockPtr)
        {
            // Socket底层扩展基础函数调用 - 发送字节码
            var GreetingTCP = string.Format("欢迎来到我的`双工客户端`");
            GreetingTCP += GREETING + Environment.NewLine;
            SockBlockPtr.QosSend(GreetingTCP);
        }

        /// <summary>
        /// 文件传输管道 步进式传输 1.发送文件清单 2.传输文件管道 3.发送传输完毕指令集
        /// </summary>
        /// <param name="sockRef"> 文件描述符 </param>
        /// <returns> 传输总字节数转换之后的自然语言描述 </returns>
        private void translateFile(Socket sockRef,string receivingMsg)
        {
            var tool = new IOUtilWorkFlow();
            var results = tool.ScanFolderV2(null,false).Where(item => item.IoCate == IOType.isFile).OrderBy(file => file.hook.Extension).ThenBy(file => file.hook.Name);

            var tokens = receivingMsg.Split(Convert.ToChar(Tokenizer.TSeper));
            Console.WriteLine("步进命令提交 -> "+tokens.Length + 0);

            // 1.发送清单 2.接收等待 3.开启传输 4.发送结束符
            if (tokens.Length == 1)
            {
                var 文件清单字符串 = new StringBuilder();
                int index = 1;
                文件清单字符串.AppendLine(Tokenizer.DKLine);
                results.ToList().ForEach(fileInfo => {
                    var Line = string.Format("{0}.`{1}`",index++,fileInfo.hook.Name);
                    文件清单字符串.AppendLine(Line);
                });
                文件清单字符串.AppendLine(Tokenizer.DKLine);
                byte[] codes = TCPExtension.blockCoder.GetBytes(文件清单字符串.ToString());
                int N = sockRef.QosSend(文件清单字符串.ToString());
                Console.WriteLine("Serv ------> " + N);
                return;

            }else if(tokens.Length == 2)
            {
                string voidInfo = string.Empty;
                string fileURL = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
                var SELIndex = Convert.ToInt32(tokens.ElementAt(1));
                fileURL += Path.DirectorySeparatorChar;
                fileURL += results.ElementAt(SELIndex-1).hook.Name;
                BFileTransMethod FTransMode = BFileTransMethod.SendOnce;
                long code = sockRef.TCPPacking(fileURL, FTransMode);
            }
        }

        /// <summary>
        /// 处理所有Socket通讯服务程序中的<b>心跳保活器</b>
        /// </summary>
        /// <param name="sockRef">文件描述符</param>
        /// <param name="receivingMsg">解析之后的传输流</param>
        private void HandlePing(Socket sockRef, string receivingMsg)
        {
            var message = string.Format("[{0}]---> {1}.", sockRef.RemoteEndPoint, receivingMsg);
            Console.Beep();
            Console.WriteLine(receivingMsg);
            sockRef.QosSend(message);
        }

        #region TCP上层堆栈启动所需要用到的内核成员变量
        /* 默认最大用户数量200个 */
        static internal int MaxNodesCount;
        /* 系统在线人数上限 */
        static internal int ManagedQueueLength;
        /* 最短推送间隔 1.5秒 */
        static internal TimeSpan PushInterval { get { return TimeSpan.FromSeconds(0.618); } }
        #endregion
    }
}
